#include "pch.h"
#include "GRTXMesh.h"
#include <GGenericInfra/GPtr.h>
#include "GRTXTriangle.h"
#include <GRendererInfra/GRiObj.h>


std::vector<GSPtr<GRTXObject>> GRTXMesh::GetALLTriangles()
{
	return mTriangles;
}

HitInfo GRTXMesh::Interset(const GRTXRay& ray) const
{
	HitInfo info;
	if (Box.Intersect(ray.Orgin,ray.Dir))
	{
		info = IntersectSet(ray, mTriangles);
	}
	return info;
}

GRTXMesh::GRTXMesh(const GUSPtr<GRiObj>& pObj)
{
	auto world = pObj->GetComponent<GRiCmpTransform>()->GetWorldMat();
	auto worldInvTranspose = world.Inverse().Transpose();

	auto& mat = pObj->GetComponent<GRiCmpMaterial>()->Mat;

	GMath::Vector3 emission(0.0f);
	if (pObj->HasComponent<GRiCmpLight>())
	{
		auto pLigh = pObj->GetComponent<GRiCmpLight>()->pLight.get();
		emission = pLigh->Color * pLigh->Intensity;
	}
	
	auto meshData = pObj->GetComponent<GRiCmpGeometry>()->GetMesh()->MeshData;
	mTriangles.resize(meshData.Indices.size() / 3);
	for (size_t i = 0; i < mTriangles.size(); i++)
	{
		auto& v0 = meshData.Vertices[meshData.Indices[3 * i]];
		auto& v1 = meshData.Vertices[meshData.Indices[3 * i + 1]];
		auto& v2 = meshData.Vertices[meshData.Indices[3 * i + 2]];

		auto worldV0 = TransformVertexToWorldSpace(v0,world,worldInvTranspose);
		auto worldV1 = TransformVertexToWorldSpace(v1,world,worldInvTranspose);
		auto worldV2 = TransformVertexToWorldSpace(v2,world,worldInvTranspose);
	
		GUSPtr<GRTXTriangle> tri = new GRTXTriangle(worldV0, worldV1, worldV2, &mat, emission);
		mTriangles[i] = (GSPtr<GRTXTriangle>(tri));
		
		Area += tri->GetArea();
		Box.Union(tri->GetBox());
	}

}

bool GRTXMesh::IsLight() const
{
	return mTriangles[0]->IsLight();
}

void GRTXMesh::SampleLight(GRiVertex& samplePos, float& pdf) const
{
	assert(IsLight());
	
	auto randomArea = GGiEngineUtil::GetRandom() * Area;
	
	for (auto tri:mTriangles)
	{
		randomArea -= tri->GetArea();
		if (randomArea <= 0)
		{
			tri->SampleLight(samplePos, pdf);
			break;
		}
	}

	// 采样面积设置为整个物体的表面积
	pdf = 1.0f / Area;
}

GRiVertex GRTXMesh::TransformVertexToWorldSpace(const GRiVertex& vertex, const GMath::Matrix& World, const GMath::Matrix& worldInvTranspose)
{
	GRiVertex wV = vertex;
	wV.Position = GMath::Vector4(vertex.Position, 1.0f) * World;
	wV.Normal = GMath::Vector4(vertex.Normal, 0.0f) * worldInvTranspose;
	wV.TangentU = GMath::Vector4(vertex.TangentU, 0.0f) * World;

	return wV;
}
